package edu.hawaii.halealohacli.command;

import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertSame;
import static org.junit.Assert.assertTrue;
import javax.xml.datatype.XMLGregorianCalendar;
import org.junit.Test;
import org.wattdepot.client.WattDepotClient;
import org.wattdepot.resource.source.jaxb.Source;
import org.wattdepot.util.tstamp.Tstamp;

/**
 * Tests the MonitorGoal class to determine if it behaves properly.
 * Proper behavior includes storing the baselines for given sources and correctly
 * reporting if a particular power conservation goal was met.
 * 
 * @author Branden Ogata
 *
 */

public class TestMonitorGoal {

  /**
   * Examines the methods used in the MonitorGoal class. 
   * This depends upon the SetBaseline class working, as it creates the Baseline instances.
   * 
   * @throws Exception  Handles any errors that do occur.
   */
  
  @Test
  public void test() throws Exception {
    // SetBaseline and MonitorGoal objects to test
    SetBaseline setBaseline = new SetBaseline();
    MonitorGoal monitorGoal = new MonitorGoal();
    
    // Various data necessary for testing
    WattDepotClient client = new WattDepotClient("http://server.wattdepot.org:8190/wattdepot/");
    String ilima = "Ilima";
    Source sourceIlima = client.getSource(ilima);
    Source sourceMokihana = client.getSource("Mokihana");
    Source sourceLehua = client.getSource("Lehua-A");
    Source sourceLokelani = client.getSource("Lokelani-B");
    Source sourceAlpha = new Source();
    XMLGregorianCalendar testTimestamp = Tstamp.makeTimestamp();
    testTimestamp.setYear(2011);
    testTimestamp.setMonth(12);
    testTimestamp.setDay(1);
    testTimestamp.setHour(0);
    testTimestamp.setMinute(0);
    testTimestamp.setSecond(0);
    testTimestamp.setMillisecond(0);    
    XMLGregorianCalendar testToday = Tstamp.makeTimestamp();
    double powerConsumption;

    // Sets up a few Baseline objects within setBaseline
    setBaseline.printResults(client, sourceIlima, testTimestamp);
    setBaseline.printResults(client, sourceMokihana, testTimestamp);
    setBaseline.printResults(client, sourceLehua, testTimestamp);
    setBaseline.printResults(client, sourceLokelani, testTimestamp);  

    // Adds Baseline objects to MonitorGoal
    monitorGoal.addBaseline(setBaseline.getBaseline(ilima));
    monitorGoal.addBaseline(setBaseline.getBaseline("Mokihana"));
    monitorGoal.addBaseline(setBaseline.getBaseline("Lehua-A"));
    monitorGoal.addBaseline(setBaseline.getBaseline("Lokelani-B"));  
    
    // Sets goal in MonitorGoal as 8% and tests that the goal is properly set
    monitorGoal.setGoal(8);
    assertSame("Testing goal", monitorGoal.getGoal(), 8);
    
    // Tests that the baseline for Ilima was added
    monitorGoal.printResults(client, sourceIlima, testTimestamp);
    assertTrue("Testing Ilima Addition", monitorGoal.getLatestResult().startsWith("On "));
    
    // Tests if the calculations for goal attainment with Ilima are correct
    powerConsumption = client.getLatestPowerConsumed(ilima) / 1000;
    
    // If the power consumption is less than the goal, then the goal should be met
    if (powerConsumption < (setBaseline.getBaseline(ilima).getValues()[testToday.getHour()] - 
                            (setBaseline.getBaseline(ilima).getValues()[testToday.getHour()] *
                              monitorGoal.getGoal() * 0.01))) {
      assertTrue("Testing Ilima, passed goal", monitorGoal.getLatestResult().contains("meets"));
      
      // If the goal was met, then test the case where the goal was not met
      // This will fail if the source has somehow decreased power consumption over 99 percent
      monitorGoal.setGoal(99);
      monitorGoal.printResults(client, sourceIlima, testTimestamp);
      assertFalse("Testing Ilima, should fail goal", 
                  monitorGoal.getLatestResult().contains("meets"));
    }
    // Else the goal was not met
    else {
      assertTrue("Testing Ilima, failed goal", monitorGoal.getLatestResult().contains("does not "));
      
      // If the goal was not met, then test the case where the goal was met
      // To ensure this, a false Baseline is created
      double[] falseValues = new double[24];
      
      for (int i = 0; i < 24; i++) {
        falseValues[i] = powerConsumption * 2;
      }
      
      Baseline decoy = new Baseline("Ilima", "2011-02-25", falseValues);
      monitorGoal.addBaseline(decoy);
      monitorGoal.printResults(client, sourceIlima, testTimestamp);
      
      assertFalse("Testing Ilima, should pass goal", 
                  monitorGoal.getLatestResult().contains("does not"));
    }

    // Tests with invalid input
    monitorGoal.printResults(client, sourceAlpha, testTimestamp);
    assertTrue("Testing invalid input", 
                monitorGoal.getLatestResult().contains("could not be found"));
  }

}
